#include "CBondInfoImpl.h"


template<>  inline int GetTypeEncoding<CBondInfoImpl::FieldFlag>(){ return (kFieldDataTypeChar << 16) + sizeof(CBondInfoImpl::FieldFlag); }

#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
#define FIELD_OFFSET(type, field)    offsetof(type, field)
#define CASE_SYNC(FIELD) case FIELD_OFFSET(CBondInfoImpl, FIELD):if (write){FIELD.Write(input, len);}else{return FIELD.Read();};break;
#define CASE_SYNC_TYPE(FIELD,TYPE) case FIELD_OFFSET(CBondInfoImpl, FIELD):if (write){FIELD = *((TYPE*)input);}else{return (const char*)(&FIELD);};break;

#define CASE_INFO(FIELD) case FIELD_OFFSET(CBondInfoImpl, FIELD):\
	if(mode==FieldModeBytes){return FIELD.GetDirectMemSize();}\
	if(mode==FieldModeSharedBytes){return FIELD.GetSharedMemSize();}\
	if(mode==FieldModeCategory){return FIELD.Category();}\
	if(mode==FieldModeType){return FIELD.TypeEncoding();}\
	if(mode==FieldModeName){memcpy(name,#FIELD,strlen(#FIELD));return RTL_FIELD_SIZE(CBondInfoImpl, FIELD);}\
	break;

#define CASE_INFO_TYPE(FIELD,TYPE) case FIELD_OFFSET(CBondInfoImpl, FIELD):\
	if(mode==FieldModeBytes){return sizeof(TYPE);}\
	if(mode==FieldModeCategory){return 0;}\
	if(mode==FieldModeType){return GetTypeEncoding<TYPE>();}\
	if(mode==FieldModeName){memcpy(name,#FIELD,strlen(#FIELD));return RTL_FIELD_SIZE(CBondInfoImpl, FIELD);}\
	break;

int	CBondInfoImpl::GetMemoryBytes(int& validbytes)const
{
	validbytes = sizeof(CBondInfoImpl);
	return validbytes;
}
int CBondInfoImpl::GetAllFields(std::vector<FieldInfo>& fields)const
{
	char buf[1024] = { 0 };
	for (int i = 0; i < sizeof(CBondInfoImpl);)
	{
		memset(buf, 0, 1024);
		int size = GetFieldInfo(i, buf, FieldModeName);
		if (size > 0)
		{
			FieldInfo fi;
			fi.index = fields.size();
			fi.offset = i;
			fi.size = size;
			fi.name = buf;
			if (fields.size() > 0)
			{
				FieldInfo& last = fields[fields.size() - 1];
				last.gap = fi.offset - (last.offset + last.size);
			}
			fields.push_back(fi);
			i += fi.size;
		}
		else
			i++;
	}
	if (fields.size() > 0)
	{
		FieldInfo& last = fields[fields.size() - 1];
		last.gap = sizeof(CBondInfoImpl) - (last.offset + last.size);
	}
	return fields.size();
}
int CBondInfoImpl::GetFieldInfo(int offset, char* name, FieldAccessMode mode)const
{
	switch (offset)
	{
		//CASE_INFO(m_sJianpin);
		//CASE_INFO(m_sQuanpin);
		CASE_INFO(m_ConversionRate);
		CASE_INFO(m_sBidLimitBottom);
		CASE_INFO(m_sBidLimitTop);
		CASE_INFO(m_IssueRate);
		CASE_INFO(m_sCouponRateCurrent);
		CASE_INFO(m_sFullName);
		CASE_INFO(m_sFullNameEn);
		CASE_INFO(m_sShortName);
		CASE_INFO(m_sShortNameEn);
		CASE_INFO(m_sCombBondKey);
		CASE_INFO(m_sBondKey);
		CASE_INFO(m_sCombBondID);
		CASE_INFO(m_sRemainDate);
		CASE_INFO(m_sRemainDateDisplay);
		CASE_INFO(m_sTermToMaturity);
		CASE_INFO(m_sIssueEndTime);
		CASE_INFO(m_sAuctionDateTime);
		CASE_INFO(m_NextCoupon_Date);
		CASE_INFO(m_PlannedExerciseDate);
		CASE_INFO(m_sAuctionDateEnd);
		CASE_INFO(m_sOptionDate);
		CASE_INFO(m_sAuctionDateStart);
		CASE_INFO(m_sIssueEndDate);
		CASE_INFO(m_sPaymentDate);
		CASE_INFO(m_sAnnounceDate);
		CASE_INFO(m_sIssueStartDate);
		CASE_INFO(m_sInterestStartDate);
		CASE_INFO(m_sListDate);
		CASE_INFO(m_sMaturityDate);
		CASE_INFO(m_sYieldCurveType);
		CASE_INFO(m_sJointUnderwriters);
		CASE_INFO(m_sUnderwrites);
		CASE_INFO(m_sIssuerRatingInstitutionCode);
		CASE_INFO(m_sAuction_Unit);
		CASE_INFO(m_sIssueType);
		CASE_INFO(m_sOutlook);
		CASE_INFO_TYPE(m_sListedMarket, qb::base::KeyString);
		CASE_INFO(m_sOptionType);
		CASE_INFO(m_sAutcionType);
		CASE_INFO(m_sEntCor);
		CASE_INFO(m_sInstitutionType);
		CASE_INFO(m_sMarketType);
		CASE_INFO(m_sBondSubType);
		CASE_INFO(m_sInterestBasis);
		CASE_INFO(m_sCouponFrequency);
		CASE_INFO(m_sCompoundFrequency);
		CASE_INFO(m_sWarrant);
		CASE_INFO(m_sMainUnderwriters);
		CASE_INFO(m_sIssuePeriod);
		CASE_INFO(m_sAuction_Step);
		CASE_INFO(m_sFRNIndexID);
		CASE_INFO(m_sIssuerRating);
		CASE_INFO(m_sBondRating);
		CASE_INFO(m_sInstitutionRating);
		CASE_INFO(m_sRateType);
		CASE_INFO(m_sCouponType);
		CASE_INFO(m_sMaturityTerm);
		CASE_INFO(m_sBondID);
		//CASE_INFO(m_sCSCleanPrice);
		//CASE_INFO(m_sCSYield);
		CASE_INFO(m_sAuction_Cap);
		CASE_INFO(m_sAuction_Flr);
		CASE_INFO(m_sFixingMADays);
		//CASE_INFO(m_sCSModifyDuration);
		CASE_INFO(m_sIssuerCode);
		CASE_INFO_TYPE(m_sAssetStatus, qb::base::KeyString);
		CASE_INFO_TYPE(m_sPrincipayPayType, qb::base::KeyString);
		CASE_INFO_TYPE(m_fPlannedIssueAmount,double);
		CASE_INFO_TYPE(m_fActualIssueAmount, double);
		CASE_INFO_TYPE(m_fOutstandingAmount, double);
		CASE_INFO_TYPE(m_nBondFileNum,int);
		CASE_INFO_TYPE(m_nAdditionInfoIndex,int);
		CASE_INFO_TYPE(m_nOptionInfoIndex, int);
		//CASE_INFO_TYPE(m_nCSDate, UINT);
		CASE_INFO_TYPE(m_nAuctionTimeStart, int);
		CASE_INFO_TYPE(m_nAuctionTimeEnd,int);
		CASE_INFO_TYPE(m_nCdcAuth, int);
		CASE_INFO_TYPE(m_flag, unsigned short);
	default:
		break;
	}
	return 0;
}
void CBondInfoImpl::WriteField(int offset, const char* str, int len)
{
	SyncField(offset, str, len, true);
}

int CBondInfoImpl::ReadField(int offset, void* buf, int capcity, int& type)const
{
	// 要求buf足够大,此处对buf不做检查
	// 读取到的数据是原始CBondContainer也能读取到的数据
	CBondInfoImpl* object = const_cast<CBondInfoImpl*>(this);
	const char* data = object->SyncField(offset, 0, 0, false);
	type = GetFieldType(offset);
	kFieldDataType datatype = (kFieldDataType)(type >> 16);
	int arrayLength = type & 0x0000ffff;

	// GetStorageBytes返回的是字符串所占内存加额外指针等内存
	// 对于非kFieldDataTypeChar,kFieldDataTypeString类型,都为原始字段
	// 原始字段的大小可以通过GetStorageBytes来获取
	int size = 0;
	if (datatype == kFieldDataTypeString)
	{
		size = strlen(data);
	}
	else if (datatype == kFieldDataTypeChar && arrayLength>0)
	{
		size = strlen(data);
	}
	else
	{
		switch (datatype)
		{
		case	kFieldDataTypeBool:size = 1; break;
		case	kFieldDataTypeChar:size = sizeof(char); break;
		case	kFieldDataTypeShort:size = sizeof(short); break;
		case	kFieldDataTypeUShort:size = sizeof(short); break;
		case	kFieldDataTypeInt:size = sizeof(int); break;
		case	kFieldDataTypeUINT:size = sizeof(UINT); break;
		case	kFieldDataTypeFloat:size = sizeof(float); break;
		case	kFieldDataTypeDouble:size = sizeof(double); break;
		default:	break;
		}
	}
	if (size>0)
		memcpy(buf, data, size);
	((char*)buf)[size] = 0;
	return size;
}
int	CBondInfoImpl::GetFieldByOffset(int offset, void* buf, int capcity, int& type)const
{
	return ReadField(offset, buf, capcity, type);
}
int CBondInfoImpl::GetStorageBytes(int offset)const
{
	// 获取指定列的存储对象的内存总和(不是一个,是所有之和)
	return GetFieldInfo(offset, 0, FieldModeBytes);
}
int CBondInfoImpl::GetFieldCategory(int offset)const
{
	return GetFieldInfo(offset, 0, FieldModeCategory);
}
int CBondInfoImpl::GetFieldType(int offset)const
{
	return GetFieldInfo(offset, 0, FieldModeType );
}
const char* CBondInfoImpl::SyncField(int offset, const char* input, int len, bool write)
{
	switch (offset)
	{
		//CASE_SYNC(m_sJianpin);
		//CASE_SYNC(m_sQuanpin);
		CASE_SYNC(m_ConversionRate);
		CASE_SYNC(m_sBidLimitBottom);
		CASE_SYNC(m_sBidLimitTop);
		CASE_SYNC(m_IssueRate);
		CASE_SYNC(m_sCouponRateCurrent);
		CASE_SYNC(m_sFullName);
		CASE_SYNC(m_sFullNameEn);
		CASE_SYNC(m_sShortName);
		CASE_SYNC(m_sShortNameEn);
		CASE_SYNC(m_sCombBondKey);
		CASE_SYNC(m_sBondKey);
		CASE_SYNC(m_sCombBondID);
		CASE_SYNC(m_sRemainDate);
		CASE_SYNC(m_sRemainDateDisplay);
		CASE_SYNC(m_sTermToMaturity);
		CASE_SYNC(m_sIssueEndTime);
		CASE_SYNC(m_sAuctionDateTime);
		CASE_SYNC(m_NextCoupon_Date);
		CASE_SYNC(m_PlannedExerciseDate);
		CASE_SYNC(m_sAuctionDateEnd);
		CASE_SYNC(m_sOptionDate);
		CASE_SYNC(m_sAuctionDateStart);
		CASE_SYNC(m_sIssueEndDate);
		CASE_SYNC(m_sPaymentDate);
		CASE_SYNC(m_sAnnounceDate);
		CASE_SYNC(m_sIssueStartDate);
		CASE_SYNC(m_sInterestStartDate);
		CASE_SYNC(m_sListDate);
		CASE_SYNC(m_sMaturityDate);
		CASE_SYNC(m_sYieldCurveType);
		CASE_SYNC(m_sJointUnderwriters);
		CASE_SYNC(m_sUnderwrites);
		CASE_SYNC(m_sIssuerRatingInstitutionCode);
		CASE_SYNC(m_sAuction_Unit);
		CASE_SYNC(m_sIssueType);
		CASE_SYNC(m_sOutlook);
		CASE_SYNC_TYPE(m_sListedMarket, qb::base::KeyString);
		CASE_SYNC(m_sOptionType);
		CASE_SYNC(m_sAutcionType);
		CASE_SYNC(m_sEntCor);
		CASE_SYNC(m_sInstitutionType);
		CASE_SYNC(m_sMarketType);
		CASE_SYNC(m_sBondSubType);
		CASE_SYNC(m_sInterestBasis);
		CASE_SYNC(m_sCouponFrequency);
		CASE_SYNC(m_sCompoundFrequency);
		CASE_SYNC(m_sWarrant);
		CASE_SYNC(m_sMainUnderwriters);
		CASE_SYNC(m_sIssuePeriod);
		CASE_SYNC(m_sAuction_Step);
		CASE_SYNC(m_sFRNIndexID);
		CASE_SYNC(m_sIssuerRating);
		CASE_SYNC(m_sBondRating);
		CASE_SYNC(m_sInstitutionRating);
		CASE_SYNC(m_sRateType);
		CASE_SYNC(m_sCouponType);
		CASE_SYNC(m_sMaturityTerm);
		CASE_SYNC(m_sBondID);
		//CASE_SYNC(m_sCSCleanPrice);
		//CASE_SYNC(m_sCSYield);
		CASE_SYNC(m_sAuction_Cap);
		CASE_SYNC(m_sAuction_Flr);
		CASE_SYNC(m_sFixingMADays);
		//CASE_SYNC(m_sCSModifyDuration);
		CASE_SYNC(m_sIssuerCode);
		CASE_SYNC_TYPE(m_sAssetStatus, qb::base::KeyString);
		CASE_SYNC_TYPE(m_sPrincipayPayType, qb::base::KeyString);
		CASE_SYNC_TYPE(m_fPlannedIssueAmount,double);
		CASE_SYNC_TYPE(m_fActualIssueAmount, double);
		CASE_SYNC_TYPE(m_fOutstandingAmount, double);
		CASE_SYNC_TYPE(m_nBondFileNum,int);
		CASE_SYNC_TYPE(m_nAdditionInfoIndex,int);
		CASE_SYNC_TYPE(m_nOptionInfoIndex, int);
		//CASE_SYNC_TYPE(m_nCSDate, UINT);
		CASE_SYNC_TYPE(m_nAuctionTimeStart, int);
		CASE_SYNC_TYPE(m_nAuctionTimeEnd,int);
		CASE_SYNC_TYPE(m_nCdcAuth, int);
		CASE_SYNC_TYPE(m_flag, unsigned short);
	default:
		break;
	}
	return 0;
}
void CBondInfoImpl::ChangeFieldMode(bool getName){  }
void CBondInfoImpl::RecordRepeatCheck()
{
// 	static DWORD lastreport = 0;
// 	struct FieldMemoryInfo{
// 		int			pod_memory;			// 直接内存大小
// 		int			shared_key;			//共享的key
// 		FieldMemoryInfo() :pod_memory(0), shared_key(0){}
// 	};
// 	if (GetTickCount() > lastreport + 20000)
// 		lastreport = GetTickCount();
// 	else
// 		return;
// 	CBondInfoImpl bond;
// 	vector<FieldInfo> fields;
// 	vector<FieldMemoryInfo> meminfos;
// 	bond.GetAllFields(fields);
// 
// 	int total = 0;
// 	meminfos.reserve(fields.size());
// 	for (int i = 0; i < (int)fields.size(); i++)
// 		meminfos.push_back(FieldMemoryInfo());
// 
// 	// 统计每一列的直接内存有多少
// 	qb::base::HighResTime timer;
// 	AfxGetBondContainer().Lock();
// 	int nsize = AfxGetBondContainer().GetSize();
// 	for (int i = 0; i < nsize; i++)
// 	{
// 		const CBondInfo& bi = AfxGetBondContainer().ElementAtR(i);
// 		for (int j = 0; j < (int)fields.size(); j++)
// 		{
// 			FieldInfo& fi = fields[j];
// 			int bytes = bi.GetStorageBytes(fi.offset);
// 			meminfos[j].pod_memory += bi.GetStorageBytes(fi.offset);
// 			total += bytes;
// 		}
// 	}
// 	AfxGetBondContainer().UnLock();
// 	qb::base::HighResTime readlast = timer.elapsed();
// 	// 统计每一列的共享内存总共有多少
// 	map<int,int> visited;
// 	for (int i = 0; i < (int)fields.size(); i++)
// 	{
// 		int offset = fields[i].offset;
// 		int category = bond.GetFieldCategory(offset);
// 		if (category==0)
// 			continue;
// 		meminfos[i].shared_key = category;
// 		if (visited.find(category) != visited.end())
// 			continue;
// 		int bytes = bond.GetFieldInfo(offset, 0, FieldModeSharedBytes);
// 		visited[category] = bytes;
// 		total += bytes;
// 	}
// 
// 	BVIEW("[NEWBONDS] 所有的CBondInfoImpl的内存统计输出如下:");
// 	BVIEW("[NEWBONDS] 总共内存:%10d  债券个数:%6d  CBondInfoOld:%d   CBondInfoImpl:%d  直接总内存:%d  全部读取耗时:%dus", total, nsize, 
// 		sizeof(CBondInfoOld), sizeof(CBondInfoImpl), sizeof(CBondInfoImpl)*nsize, readlast.microsec());
// 	BVIEW("[NEWBONDS] 直接内存是每个字段直接拥有的内存总和,共享内存是所有该字段共享的内存总和");
// 	BVIEW("[NEWBONDS] 共享key相同对应的共享内存实质上是同一份内存,如所有的日期字段");
// 	BVIEW("[NEWBONDS] %32s  ,%10s  ,%10s  ,%4s", "列", "直接内存", "共享内存", "共享key");
// 	struct MemInfo{
// 		string	name;
// 		int		bytes;
// 		int		share;
// 		int		key;
// 	public:
// 		bool operator<(const MemInfo& mi)const{return bytes > mi.bytes;}
// 	};
// 
// 	static BondChecker checker;
// 	vector<MemInfo> infos; infos.reserve(fields.size());
// 	for (int i = 0; i < (int)fields.size(); i++)
// 	{
// 		MemInfo mi; mi.name = fields[i].name;
// 		mi.bytes = meminfos[i].pod_memory;
// 		mi.share = visited[meminfos[i].shared_key];
// 		mi.key = meminfos[i].shared_key;
// 		infos.push_back(mi);
// 	}
// 	std::sort(infos.begin(), infos.end());
// 	for (int i = 0; i < (int)fields.size(); i++)
// 	{
// 		BVIEW("[NEWBONDS] %32s  ,%10d  ,%10d  ,%4d",
// 			infos[i].name.c_str(), infos[i].bytes,
// 			infos[i].share, infos[i].key
// 			);
// 	}
// 	
}
// void CBondInfoImpl::CheckEqual(CBondInfoImpl* impl, CBondInfoOld* old)
// {
// 	static BondChecker checker;
// 	checker.CheckEqual(*impl, *old);
// }

